import datetime
import pytz
import os
import csv

from flask import current_app
from .model import Camera, Preset, Path, db, WebsocketMessage
import logging

# 获取日志记录器
logger = logging.getLogger(__name__)


def get_all_cameras():
    """
    获取全部摄像头信息
    :return:
    """
    cameras = Camera.query.all()
    cameras_dict_list = [camera.to_dict() for camera in cameras]
    return cameras_dict_list


def get_camera_by_id(id):
    """
    根据摄像头id获取摄像头信息
    :param camera_id:
    :return:
    """
    camera = Camera.query.filter_by(id=id).first()
    if camera:
        return camera.to_dict()
    else:
        return None


def add_cameras(camera_list):
    """
    新增摄像头
    :param camera_list:
    :return:
    """
    for camera in camera_list:
        db.session.merge(Camera(**camera))
    try:
        db.session.commit()
        return True
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error adding cameras: {e}")
        return False
    # try:
    #     # 使用 bulk_insert_mappings 进行批量插入
    #     db.session.bulk_insert_mappings(Camera, camera_list)
    #     db.session.commit()
    #     return True
    # except Exception as e:
    #     db.session.rollback()
    #     logger.error(f"Error adding cameras: {e}")
    #     return False


# 修改摄像头基础信息，包括id，名称，视频路径，排序
def update_camera(id, camera_id, name, video_url, sort):
    """
    修改摄像头信息
    :param id
    :param camera_id:
    :param name:
    :param video_url:
    :param sort
    :return:
    """
    try:
        camera = Camera.query.filter_by(id=id).first()
        if camera:
            camera.camera_id = camera_id
            camera.name = name
            camera.video_path = video_url
            camera.sort = sort
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error updating camera: {e}")
        return False


# 修改摄像头路径配置信息，包括截图存储路径、录像存储路径、报警抓拍存储路径
def update_camera_path(id, screenshot_url, video_path, alarm_screenshot_url):
    """
    修改摄像头路径配置信息
    :param id
    :param screenshot_url:
    :param video_path:
    :param alarm_screenshot_url:
    :return:
    """
    try:
        camera = Camera.query.filter_by(id=id).first()
        if camera:
            camera.screenshot_url = screenshot_url
            camera.video_path = video_path
            camera.alarm_screenshot_url = alarm_screenshot_url
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error updating camera path: {e}")
        return False


# 修改摄像头IR参数信息，包括发射率、反射温度、环境温度、相对湿度、测温距离
def update_camera_ir(id, reflection_rate, reflection_temperature, environment_temperature, relative_humidity,
                     temperature_distance):
    """
    修改摄像头IR参数信息
    :param id
    :param reflection_rate:
    :param reflection_temperature:
    :param environment_temperature:
    :param relative_humidity:
    :param temperature_distance:
    :return:
    """
    try:
        camera = Camera.query.filter_by(id=id).first()
        if camera:
            camera.reflection_rate = reflection_rate
            camera.reflection_temperature = reflection_temperature
            camera.environment_temperature = environment_temperature
            camera.relative_humidity = relative_humidity
            camera.temperature_distance = temperature_distance
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error updating camera ir: {e}")
        return False


# 修改摄像头增益信息
def update_camera_gain(id, gain):
    """
    修改摄像头增益信息
    :param id
    :param gain:
    :return:
    """
    try:
        camera = Camera.query.filter_by(id=id).first()
        if camera:
            camera.gain = gain
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error updating camera gain: {e}")
        return False


# 修改摄像头模式信息
def update_camera_mode(id, mode):
    """
    修改摄像头模式信息
    :param id
    :param mode:
    :return:
    """
    try:
        camera = Camera.query.filter_by(id=id).first()
        if camera:
            camera.mode = mode
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error updating camera mode: {e}")
        return False


# 修改摄像头电晕颜色信息
def update_camera_color(id, color):
    """
    修改摄像头电晕颜色信息
    :param id
    :param color:
    :return:
    """
    try:
        camera = Camera.query.filter_by(id=id).first()
        if camera:
            camera.color = color
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error updating camera color: {e}")
        return False


# 修改摄像头报警设置 包括紫外光子数、红外温度
def update_camera_alarm(id, ir_photons, ir_temperature):
    """
    修改摄像头报警设置
    :param id
    :param ir_photons:
    :param ir_temperature:
    :return:
    """
    try:
        camera = Camera.query.filter_by(id=id).first()
        if camera:
            camera.ir_photons = ir_photons
            camera.ir_temperature = ir_temperature
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error updating camera alarm: {e}")
        return False


# 修改摄像头转动速度
def update_camera_speed(id, speed):
    """
    修改摄像头转动速度
    :param id
    :param speed:
    :return:
    """
    try:
        camera = Camera.query.filter_by(id=id).first()
        if camera:
            camera.speed = speed
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error updating camera speed: {e}")
        return False


# 查询摄像头的预制点
def get_camera_preset(id):
    """
    查询摄像头的预制点
    :param id
    :return:
    """
    presets = Preset.query.filter_by(camera_id=id).all()
    presets_dict_list = [preset.to_dict() for preset in presets]
    return presets_dict_list


# 添加摄像头预制点
def add_camera_preset(camera_id, preset_name, uid):
    """
    添加摄像头预制点
    :param camera_id
    :param preset_name:
    :return:
    """
    try:
        preset = Preset(camera_id=camera_id, name=preset_name, uid=uid)
        db.session.add(preset)
        db.session.commit()
        return True
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error adding camera preset: {e}")
        return False


# 删除摄像头预置点名称
def del_camera_preset(id):
    """
    删除摄像头预置点名称
    :param id
    :return:
    """
    try:
        preset = Preset.query.filter_by(id=id).first()
        if preset:
            db.session.delete(preset)
            db.session.commit()
            return True
        else:
            return False
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error deleting camera preset: {e}")
        return False


# 查询摄像头路径巡航点
def get_camera_path_byid(id):
    """
    查询摄像头路径巡航点
    :param id
    :return:
    """
    path = Path.query.filter_by(camera_id=id).first()
    if path:
        path_dict = path.to_dict()
        # 再查一下每一个preset_id的详细点信息
        preset_ids_list = path_dict.get('preset_ids')
        # 根据id查preset表,最终结果是id的顺序
        presets = Preset.query.filter(Preset.id.in_(preset_ids_list)).all()
        # 按照 preset_ids_list 的顺序排序
        sorted_presets = sorted(presets, key=lambda x: preset_ids_list.index(x.id))
        path_dict['presets'] = [preset.to_dict() for preset in sorted_presets]
        return path_dict
    else:
        return None


# 添加摄像头路径巡航点
def add_camera_path(path_id, camera_id, preset_ids, interval):
    """
    添加摄像头路径巡航点
    :param path_id:
    :param camera_id
    :param preset_ids:
    :param interval:
    :return:
    """
    try:
        preset_ids_str = ','.join(map(str, preset_ids))
        # id 存在则更新 为空则新增
        if path_id:
            path = Path.query.filter_by(id=path_id).first()
            if path:
                path.preset_ids = preset_ids_str
                path.interval = interval
                db.session.commit()
                return True
            else:
                return False
        else:
            path = Path(camera_id=camera_id, preset_ids=preset_ids_str, interval=interval)
            db.session.add(path)
            db.session.commit()
            return True
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error adding camera path:{e}")
        return False


# 保存websocket消息
def save_websocket_message(message):
    """
    保存websocket消息
    :param message: websocket消息
    :return: 成功时返回True，失败时返回False
    """
    try:
        # message为object，取值camera_id，ir_photons，ir_temperature，date
        camera_id = message.get("cameraId")
        ir_photons = message.get("data").get("uv")
        ir_temperature = message.get("data").get("temperature")
        date = message.get("data").get("date")
        alarm = 0
        # 查询告警值设置
        camera = Camera.query.filter_by(camera_id=camera_id).first()
        if camera.ir_photons is not None \
                and camera.ir_temperature is not None \
                and (int(ir_photons) > int(camera.ir_photons) or int(ir_temperature) > int(camera.ir_temperature)):
            alarm = 1
        websocket_message = WebsocketMessage(camera_id=camera.id,
                                             alarm_photons=camera.ir_photons,
                                             alarm_temperature=camera.ir_temperature,
                                             gain=camera.gain,
                                             ir_photons=ir_photons,
                                             ir_temperature=ir_temperature,
                                             date=date,
                                             alarm=alarm)
        db.session.add(websocket_message)
        db.session.commit()
        return True
    except Exception as e:
        db.session.rollback()
        logger.error(f"Error saving websocket message: {e}")
        return False


# 查询websocket消息 camera_id和date，数组
def get_websocket_messages(camera_id, date):
    """
    查询websocket消息
    :param camera_id: 摄像头ID
    :param date: 日期
    :return: 成功时返回websocket消息数组，失败时返回None及错误信息
    """
    try:
        shanghai_tz = pytz.timezone('Asia/Shanghai')
        today = datetime.datetime.now(shanghai_tz).strftime("%Y-%m-%d")
        logger.info(f"today: {today}")
        # date默认传今天，设置了date就传制定日期的websocket消息，日期格式YYYY-MM-DD，模糊搜索
        _date = date if date else today
        messages = WebsocketMessage.query.filter(WebsocketMessage.camera_id == camera_id,
                                                 WebsocketMessage.date.like(f"%{_date}%")).all()
        messages_dict_list = [message.to_dict() for message in messages]
        return messages_dict_list
    except Exception as e:
        logger.error(f"Error getting websocket messages: {e}")
        return None


# 文件上传接口
def upload_file(camera_id, type, file):
    """
    文件上传接口
    :param camera_id: 摄像头ID
    :param type: 文件类型 ('1': 截图, '2': 录像, '3': 报警抓拍)
    :param file: 上传的文件对象
    :return: 成功时返回文件路径，失败时返回None及错误信息
    """
    try:
        # 获取文件名
        filename = file.filename
        # 文件路径直接读取摄像头路径配置信息，包括截图存储路径、录像存储路径、报警抓拍存储路径
        camera = Camera.query.filter_by(id=camera_id).first()
        if camera:
            if type == '1':
                save_path = os.path.join('screenshot/common', filename)
            elif type == '2':
                save_path = os.path.join('screenshot/video', filename)
            elif type == '3':
                save_path = os.path.join('screenshot/alarm', filename)
            else:
                logger.error(f"Invalid type: {type}")
                return False
                # 确保目录存在
            os.makedirs(os.path.dirname(save_path), exist_ok=True)
            file.save(save_path)
            return True
        else:
            logger.error(f"Camera not found: {id}")
            return False
    except Exception as e:
        logger.error(f"Error uploading file: {e}")
        return False


# 定时任务主动保存当天的摄像头数据，光子数，温度值，增益，时间，是否告警
def save_daily_camera_data():
    """
    定时任务：保存当天的摄像头数据到CSV文件
    :return: 成功时返回True，失败时返回False
    """
    try:
        shanghai_tz = pytz.timezone('Asia/Shanghai')
        today = datetime.datetime.now(shanghai_tz).strftime("%Y-%m-%d")

        # 查询所有摄像头
        cameras = Camera.query.all()
        for camera in cameras:
            # 查询当天的WebSocket消息
            messages = WebsocketMessage.query.filter(
                WebsocketMessage.camera_id == camera.id,
                WebsocketMessage.date.like(f"%{today}%")
            ).all()
            logger.info(f"Camera {camera.id} messages: {messages}")
            # if not messages:
            #     continue

            # 构造文件名
            filename = f"{camera.name}_{today}.csv"
            filepath = os.path.join("data", "daily_reports", filename)
            os.makedirs(os.path.dirname(filepath), exist_ok=True)

            # 写入CSV文件
            with open(filepath, mode='w', newline='', encoding='utf-8') as file:
                writer = csv.writer(file)
                # 写入表头
                writer.writerow(["光子数告警值", "温度告警值", "实时光子数", "实时温度值", "增益", "时间", "是否告警"])
                # 写入数据
                for message in messages:
                    writer.writerow([
                        camera.ir_photons,
                        camera.ir_temperature,
                        message.ir_photons,
                        message.ir_temperature,
                        camera.gain,  # 增益从摄像头信息中获取
                        message.date,
                        "正常" if (message.alarm == 0) else "异常"
                    ])
            logger.info(f"Daily camera data saved to {filepath}")
        return True
    except Exception as e:
        logger.error(f"Error saving daily camera data: {e}")
        return False